/**
 * EntityDaoImpl.java
 * com.opsys.api.common.dao.hibernate
 *
 * Function：(一句话功能说明) 
 *
 *  version      date      		  author
 * ──────────────────────────────────────
 *  Ver 1.0  2013-11-5    CWL
 *
 * Copyright(c) 2013, PUKKA All Rights Reserved.
 */

package com.zhehekeji.opsys.api.common.dao;

import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


/**
 * (一句话功能说明)
 * 
 * @author CWL
 * @version 1.0
 * @see
 * @since 1.0
 * @Date 2013-11-5 下午2:20:06
 */
@Repository(value = "entityDao")
public class EntityDaoImpl implements EntityDao {

	@PersistenceContext
	protected EntityManager em;
	protected static final int MAX_RESULT = 9999;
	
	@Override
	public <T> T get(Class<T> entityClass, Object entityid)  throws SQLException{
		return em.find(entityClass, entityid);

	}

	/**
	 * (non-Javadoc)
	 * @see EntityDao#get(java.lang.Class, java.lang.String, java.lang.Object[])
	 */
	@Override
	public <T> T get(Class<T> entityClass, String wherejpql,
			Object[] queryParams) throws SQLException {
		List<T> result = this.getScrollData(entityClass, 0, 1, wherejpql, queryParams);
		return result!=null && !result.isEmpty() ? result.get(0) : null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> getScrollData(Class<T> entityClass, int firstindex,
			int maxresult, String wherejpql, Object[] queryParams,
			LinkedHashMap<String, String> orderby)  throws SQLException {

		Query query = em.createQuery("SELECT o FROM "
				+ getEntityName(entityClass) + " o "
				+ (wherejpql == null ? "" : "WHERE " + wherejpql)
				+ buildOrderby(orderby));
		setQueryParams(query, queryParams);
		if (firstindex != -1 && maxresult != -1){
			query.setFirstResult(firstindex).setMaxResults(getMaxResult(maxresult));
		}else{
			query.setFirstResult(0).setMaxResults(getMaxResult(maxresult));
		}

		return query.getResultList();
	}

	@Override
	public <T> List<T> getScrollData(Class<T> entityClass, int firstindex,
			int maxresult, String wherejpql, Object[] queryParams)   throws SQLException{

		return getScrollData(entityClass, firstindex, maxresult, wherejpql,
				queryParams, null);

	}

	@Override
	public <T> List<T> getScrollData(Class<T> entityClass, int firstindex,
			int maxresult, LinkedHashMap<String, String> orderby)  throws SQLException {

		return getScrollData(entityClass, firstindex, maxresult, null, null,
				orderby);

	}

	@Override
	public <T> List<T> getScrollData(Class<T> entityClass, int firstindex,
			int maxresult)   throws SQLException{

		return getScrollData(entityClass, firstindex, maxresult, null, null,
				null);

	}

	@Override
	public <T> List<T> getScrollData(Class<T> entityClass, String wherejpql,
			Object[] queryParams)   throws SQLException{

		return getScrollData(entityClass, -1, -1, wherejpql, queryParams, null);
	}

	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	@Override
	public <T> List<T> getScrollData(Class<T> entityClass)   throws SQLException{

		return getScrollData(entityClass, -1, -1, null, null, null);

	}
	
	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> getScrollDataByJpql(Class<T> entityClass, String jpql,
			Object[] queryParams, int firstindex, int maxresult)
			throws SQLException {
		if (StringUtils.isEmpty(jpql)) {
			return null;
		}
		Query query = em.createQuery(jpql, entityClass);
		setQueryParams(query, queryParams);
		if (firstindex != -1 && maxresult != -1){
			query.setFirstResult(firstindex).setMaxResults(getMaxResult(maxresult));
		}else{
			query.setFirstResult(0).setMaxResults(getMaxResult(maxresult));
		}
		return query.getResultList();
	}

	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	@Override
	public List<Map<String, Object>> getScrollDataByHql(String hql,
			Object[] queryParams, int firstindex, int maxresult)   throws SQLException{
		if (StringUtils.isEmpty(hql)) {
			return null;
		}
		Session session = (Session) em.getDelegate();
		org.hibernate.Query query = session.createQuery(hql);
		if (queryParams != null && queryParams.length > 0) {
			for (int i = 0; i < queryParams.length; i++) {
				query.setParameter(i, queryParams[i]);
			}
		}
		if (firstindex != -1 && maxresult != -1){
			query.setFirstResult(firstindex).setMaxResults(getMaxResult(maxresult));
		}else{
			query.setFirstResult(0).setMaxResults(getMaxResult(maxresult));
		}
		@SuppressWarnings("unchecked")
		List<Map<String, Object>> results = query.setResultTransformer(
				Criteria.ALIAS_TO_ENTITY_MAP).list();
		return results;

	}

	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	@Override
	public List<Map<String, Object>> getScrollDataBySql(String sql,
			Object[] queryParams, int firstindex, int maxresult)  throws SQLException {
		if (StringUtils.isEmpty(sql)){
			return null;
		}
		Session session = (Session) em.getDelegate();
		org.hibernate.SQLQuery query = session.createSQLQuery(sql);
		if (queryParams != null && queryParams.length > 0){
			for (int i = 0; i < queryParams.length; i ++){
				query.setParameter(i, queryParams[i]);
			}
		}
		if(firstindex!=-1 && maxresult!=-1){
			query.setFirstResult(firstindex).setMaxResults(getMaxResult(maxresult));
		}else{
			query.setFirstResult(0).setMaxResults(getMaxResult(maxresult));
		}
		@SuppressWarnings("unchecked")
		List<Map<String, Object>> results =	query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP).list();
		return results;

	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	@Override
	public <T> List<T> getScrollDataBySql(Class<T> entityClass, String sql,
			Object[] queryParams, int firstindex, int maxresult)
			throws SQLException {
		if (StringUtils.isEmpty(sql)){
			return null;
		}
		Query query = em.createNativeQuery(sql, entityClass);
		if (queryParams != null && queryParams.length > 0){
			for (int i = 0; i < queryParams.length; i ++){
				query.setParameter(i, queryParams[i]);
			}
		}
		if(firstindex!=-1 && maxresult!=-1){
			query.setFirstResult(firstindex).setMaxResults(getMaxResult(maxresult));
		}else{
			query.setFirstResult(0).setMaxResults(getMaxResult(maxresult));
		}
		return query.getResultList();
	}

	/**
	 * 组装query.setParameter(int arg0, Object arg1) 参数
	 * 
	 * @param query
	 * @param queryParams
	 */
	protected void setQueryParams(Query query, Object[] queryParams) {
		if (queryParams != null && queryParams.length > 0) {
			for (int i = 0; i < queryParams.length; i++) {
				query.setParameter(i + 1, queryParams[i]);
			}
		}
	}

	/**
	 * 组装 orderby语句
	 * 
	 * @param orderby
	 * @return
	 */
	protected String buildOrderby(LinkedHashMap<String, String> orderby) {
		StringBuffer orderbyql = new StringBuffer("");
		if (orderby != null && orderby.size() > 0) {
			orderbyql.append(" ORDER BY ");
			for (String key : orderby.keySet()) {
				orderbyql.append("o.").append(key).append(" ")
						.append(orderby.get(key)).append(",");
			}
			orderbyql.deleteCharAt(orderbyql.length() - 1);
		}
		return orderbyql.toString();
	}

	/**
	 * 获取实体名称
	 * 
	 * @param <T>
	 * @param entityClass
	 *            实体类
	 * @return
	 */
	protected <T> String getEntityName(Class<T> entityClass) {
		// 默认实体名称
		String entityname = entityClass.getSimpleName();
		// 取得自定义实体名称
		Entity entity = entityClass.getAnnotation(Entity.class);
		if (entity.name() != null && !"".equals(entity.name())) {
			entityname = entity.name();
		}
		return entityname;
	}

	protected int getMaxResult(int maxResult){
		if (maxResult == -1 || maxResult == 0){
			return MAX_RESULT;
		}
		if (maxResult > MAX_RESULT){
			return MAX_RESULT;
		}
		return maxResult;
	}
	
	@Transactional
	@Override
	public Integer save(Object entity) {
		Session session = (Session) em.getDelegate();
		Integer id = (Integer)session.save(entity);
		return id;
	}

	/**
	 * (non-Javadoc)
	 * @see EntityDao#saveObj(java.lang.Object)
	 */
	@Transactional
	@Override
	public Long saveObj(Object entity) {
		Session session = (Session) em.getDelegate();
		Long id = (Long)session.save(entity);
		return id;
		
	}

	@Transactional
	@Override
	public void saveVoid(Object entity) {
		em.persist(entity);
	}

	/**
	 * (non-Javadoc)
	 * @see EntityDao#update(java.lang.Object)
	 */
	@Transactional
	@Override
	public boolean update(Object entity) {
		
		return em.merge(entity) == null ? false : true;
	}
	@Transactional
	@Override
	public void delete(Object entity) {
		
		em.remove(entity);
	}
	@Transactional
	@Override
	public void deleteDetached(Object entity) {
		
		em.remove(em.contains(entity) ? entity : em.merge(entity));
	}

	@Override
	public EntityManager getEntityManager() {
		return em;
	}
}
